//
// Convention1JavaParams
//
// Copyright (C) jextra.net.
//
//  This file is part of the Crack build system.
//
//  The Crack build system is free software; you can redistribute it 
//  and/or modify it under the terms of the GNU Lesser General Public
//  License as published by the Free Software Foundation; either
//  version 2.1 of the License, or (at your option) any later version.
//
//  The Crack build system is distributed in the hope that it will be 
//  useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
//  Lesser General Public License for more details.
//
//  You should have received a copy of the GNU Lesser General Public
//  License along with the Crack build system; if not, write to the Free
//  Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
//  02111-1307 USA.
//

package net.jextra.crack.java;

import java.io.*;
import java.util.*;
import net.jextra.crack.*;
import net.jextra.crack.props.*;
import net.jextra.crack.tool.*;
import net.jextra.crack.type.*;

/**
 * <p>
 * A "standard" convention of directories for development of Java code.
 * </p>
 * <p>
 * These parameters assume a standard directory structure of:
 * </p>
 * 
 * <pre>
 * PROJECT_ROOT_DIR/
 *     env - Environment directory for location of environment.properties file (overrides).
 *     COMPONENT_ROOT_DIR/
 *         a/b/c/ - Source code (and location of Build.crack file).
 *         a/b/d/ - Other source code (e.g. Indepdendent test directory).
 *         version.properties
 *     target/
 *         classes/ - Compiled classes.
 *         javadoc/ - JavaDoc.
 *         build/ - Directory of packaged jar files.
 *         shrinkwrap/ - Directory of staging area for deployment.
 * </pre>
 */
public class Convention1JavaParams
{
    // ============================================================
    // Fields
    // ============================================================

    public static final String DIR_ENV = "../env";
    public static final String DIR_TARGET = "../target";
    public static final String DIR_CLASSES = DIR_TARGET + "/classes";
    public static final String DIR_JAVADOC = DIR_TARGET + "/javadoc";
    public static final String DIR_BUILD_ROOT = DIR_TARGET + "/build";
    public static final String DIR_SHRINKWRAP = DIR_TARGET + "/shrinkwrap";

    public static final String FILE_VERSION_PROPERTIES = "version.properties";
    public static final String PROP_VERSION_NUMBER = "version.number";
    public static final String DEFAULT_VERSION_NUMBER = "0.0.0.0";

    private String versionNumber;
    private File projectRootDir;
    private File componentRootDir;
    private HashSet<File> sourceDirs;
    private FileSet sourceFileSet;
    private File targetDir;
    private File envDir;
    private File classesDir;
    private File javadocDir;
    private File buildDir;
    private File shrinkwrapDir;

    // ============================================================
    // Constructors
    // ============================================================

    public Convention1JavaParams()
    {
        try
        {
            //
            // Search for version.properties file in order to locate the component's root dir.
            //
            RootFinder rootFinder = new RootFinder();
            File dir = rootFinder.getRoot( CrackBuild.getInstance(), "" );
            RegexFileStrainer strainer = new RegexFileStrainer().include( ".*\\.java" );
            sourceFileSet = new StrainedFileSet( dir, strainer );

            //
            // Search for version.properties file in order to find component root. This can vary
            // from component to component (e.g. /src, /src/main/java).
            //
            componentRootDir = null;
            for ( ; dir != null; dir = dir.getParentFile() )
            {
                File vpFile = new File( dir, FILE_VERSION_PROPERTIES );
                if ( vpFile.exists() )
                {
                    componentRootDir = dir;
                    break;
                }
            }

            assert componentRootDir != null : "Unable to find " + FILE_VERSION_PROPERTIES + " in source path.";

            //
            // It is assumed that the project's root dir is always just the parent of the component root dir.
            //
            projectRootDir = componentRootDir.getParentFile();

            //
            // Find all paths to .java files in component.
            //
            sourceDirs = new LinkedHashSet<File>();
            JavaPackageFinder finder = new JavaPackageFinder();
            for ( File javaFile : strainer.getFiles( dir ) )
            {
                finder.read( javaFile );
                sourceDirs.add( finder.getRootDir() );
            }

            //
            // Read the version properties file at component root dir.
            //
            Properties versionProps = new Properties();
            File versionFile = new File( componentRootDir, FILE_VERSION_PROPERTIES );
            versionNumber = DEFAULT_VERSION_NUMBER;
            if ( versionFile.exists() )
            {
                FileInputStream in = new FileInputStream( versionFile );
                versionProps.load( in );
                in.close();
                versionNumber = (String) versionProps.get( PROP_VERSION_NUMBER );
            }

            //
            // Calculate output dirs.
            //
            envDir = new File( componentRootDir, DIR_ENV );
            targetDir = new File( componentRootDir, DIR_TARGET );
            classesDir = new File( componentRootDir, DIR_CLASSES );
            javadocDir = new File( componentRootDir, DIR_JAVADOC );
            buildDir = new File( componentRootDir, DIR_BUILD_ROOT );
            shrinkwrapDir = new File( componentRootDir, DIR_SHRINKWRAP );
        }
        catch ( Exception ex )
        {
            throw new CrackException( ex );
        }
    }

    // ============================================================
    // Methods
    // ============================================================

    // ----------
    // public
    // ----------

    public File getTargetDir()
    {
        return targetDir;
    }

    public File getProjectRootDir()
    {
        return projectRootDir;
    }

    public File getComponentRootDir()
    {
        return componentRootDir;
    }

    public void setRootDir( File rootDir )
    {
        componentRootDir = rootDir;
    }

    public Collection<File> getSourceDirs()
    {
        return sourceDirs;
    }

    public Collection<File> getResourceDirs()
    {
        return sourceDirs;
    }

    public FileSet getSourceFileSet()
    {
        return sourceFileSet;
    }

    public void clearSourceDirs()
    {
        sourceDirs.clear();
    }

    public void addSourceDir( File sourceDir )
    {
        sourceDirs.add( sourceDir );
    }

    public File getClassesDir()
    {
        if ( classesDir != null )
        {
            return classesDir;
        }

        //
        // Override classesDir if specified in Props by now.
        //
        if ( CrackProps.getString( "classes.dir" ) != null )
        {
            return new File( getComponentRootDir(), CrackProps.getString( "classes.dir" ) );
        }

        return new File( componentRootDir, DIR_CLASSES );
    }

    public void setClassesDir( File classesDir )
    {
        this.classesDir = classesDir;
    }

    public File getJavadocDir()
    {
        return javadocDir;
    }

    public void setJavadocDir( File javadocDir )
    {
        this.javadocDir = javadocDir;
    }

    public File getEnvDir()
    {
        return envDir;
    }

    public void setEnvDir( File envDir )
    {
        this.envDir = envDir;
    }

    public File getBuildDir()
    {
        return buildDir;
    }

    public void setBuildDir( File buildDir )
    {
        this.buildDir = buildDir;
    }

    public File getShrinkwrapDir()
    {
        return shrinkwrapDir;
    }

    public void setShrinkwrapDir( File shrinkwrapDir )
    {
        this.shrinkwrapDir = shrinkwrapDir;
    }

    public String getVersionNumber()
    {
        return versionNumber;
    }

    public void setVersionNumber( String versionNumber )
    {
        this.versionNumber = versionNumber;
    }
}
